/**
  ******************************************************************************
  * @file    fal_flash_stm32f0_port.c
  * @author  Iron
  * @date    2021-02-07
  * @version v1.0
  * @brief   fal_flash_stm32f0_port c file
  */

/* Private includes ----------------------------------------------------------*/
#include "bsp_flash_iap.h"
#include <fal.h>

/* BEBUG LOG */
#include "debug_log.h"
#define LOG_LOCAL_LEVEL     DBG_LOG_DEBUG
DBG_LOG_TAG("FAL_FLASH_STM32F0");

#define FAL_FLASH_STM32F0_RUNTIME_EN  1

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define FAL_FLASH_STM32F0_GRAN 32

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#if FAL_FLASH_STM32F0_RUNTIME_EN
    static int ef_err_port_cnt = 0;
    static int on_ic_read_cnt  = 0;
    static int on_ic_write_cnt = 0;
    static int on_ic_erase_cnt = 0;
#endif

/* Private function prototypes -----------------------------------------------*/
static int fal_flash_stm32f0_init(void);
static int fal_flash_stm32f0_erase(long offset, size_t size);
static int fal_flash_stm32f0_write(long offset, const uint8_t *buf, size_t size);
static int fal_flash_stm32f0_read(long offset, uint8_t *buf, size_t size);

/*----------------------------------------------------------------------------*/
/*
  "stm32_onchip" :   Flash 设备的名字。
  0x08000000:        对 Flash 操作的起始地址。
  1024*1024：        Flash 的总大小（1MB）。
  128*1024：         Flash 块/扇区大小（因为 STM32F2 各块大小不均匀，所以擦除粒度为最大块的大小：128K）。
  {init, read, write, erase} ：Flash 的操作函数。 如果没有 init 初始化过程，第一个操作函数位置可以置空。
  8 : 设置写粒度，单位 bit， 0 表示未生效（默认值为 0 ），该成员是 fal 版本大于 0.4.0 的新增成员。各个 flash 写入粒度不尽相同，可通过该成员进行设置，以下列举几种常见 Flash 写粒度：
  nor flash:  1 bit
  stm32f2/f4: 8 bit
  stm32f1:    32 bit
  stm32l4:    64 bit
*/
const struct fal_flash_dev stm32_onchip_flash =
{
    .name       = "stm32_onchip",
    .addr       = 0x08000000,
    .len        = 64 * 1024,
    .blk_size   = 1 * 1024,
    .ops        = {
        fal_flash_stm32f0_init,
        fal_flash_stm32f0_read,
        fal_flash_stm32f0_write,
        fal_flash_stm32f0_erase
    },
    .write_gran = FAL_FLASH_STM32F0_GRAN // 写粒度，单位 bit
};

/*----------------------------------------------------------------------------*/
int fal_flash_stm32f0_get_runtime(int *error_cnt, int *read_cnt, int *write_cnt, int *erase_cnt)
{
#if FAL_FLASH_STM32F0_RUNTIME_EN
    *error_cnt = ef_err_port_cnt;
    *read_cnt  = on_ic_read_cnt;
    *write_cnt = on_ic_write_cnt;
    *erase_cnt = on_ic_erase_cnt;
#endif
    return 1;
}


/*----------------------------------------------------------------------------*/
static int fal_flash_stm32f0_init(void)
{
    return 1;
}

/*----------------------------------------------------------------------------*/
static int fal_flash_stm32f0_read(long offset, uint8_t *buf, size_t size)
{
    size_t i;
    uint32_t addr = stm32_onchip_flash.addr + offset;

#if FAL_FLASH_STM32F0_RUNTIME_EN
    on_ic_read_cnt++;
#endif

    if (addr % (FAL_FLASH_STM32F0_GRAN / 8) != 0)
    {
#if FAL_FLASH_STM32F0_RUNTIME_EN
        ef_err_port_cnt++;
#endif
        DBG_LOGW(TAG, "fal flash read addr gran error.(addr=0x%08X)", addr);
    }

    for (i = 0; i < size; i++, addr++, buf++)
    {
        *buf = *(uint8_t *) addr;
    }

    return size;
}

/*----------------------------------------------------------------------------*/
static int fal_flash_stm32f0_write(long offset, const uint8_t *buf, size_t size)
{
    uint32_t addr = stm32_onchip_flash.addr + offset;

#if FAL_FLASH_STM32F0_RUNTIME_EN
    on_ic_write_cnt++;
#endif

    if (addr % (FAL_FLASH_STM32F0_GRAN / 8) != 0)
    {
#if FAL_FLASH_STM32F0_RUNTIME_EN
        ef_err_port_cnt++;
#endif

        DBG_LOGW(TAG, "fal flash read addr gran error.(addr=0x%08X)", addr);
    }

    bsp_flash_iap_write(addr, buf, size);

    return size;
}

/*----------------------------------------------------------------------------*/
static int fal_flash_stm32f0_erase(long offset, size_t size)
{
    uint32_t addr = stm32_onchip_flash.addr + offset;

#if FAL_FLASH_STM32F0_RUNTIME_EN
    on_ic_erase_cnt++;
#endif

    bsp_flash_iap_erase(addr, size);

    return size;
}


/**
  * @}
  */

/******************* (C)COPYRIGHT 2021 ***** END OF FILE *********************/
